-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: argocd version --client tries to connect server #8341
Conversation
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
Codecov Report
@@ Coverage Diff @@
## master #8341 +/- ##
==========================================
+ Coverage 41.91% 42.31% +0.40%
==========================================
Files 178 176 -2
Lines 23003 22797 -206
==========================================
+ Hits 9641 9646 +5
+ Misses 11979 11775 -204
+ Partials 1383 1376 -7
Continue to review full report at Codecov.
|
Based on #7986 (comment), the issue turns out to be a bit deeper. I think we need to improve the CLI in general such that the assumption of a valid kube context is only used when necessary. For example, is it possible to fix this such that |
EDIT: Nevermind I see this is conditionally added to commands that need to access the API server: command.AddCommand(NewCompletionCommand())
command.AddCommand(headless.InitCommand(NewVersionCmd(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewClusterCommand(&clientOpts, pathOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewApplicationCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(NewLoginCommand(&clientOpts))
command.AddCommand(NewReloginCommand(&clientOpts))
command.AddCommand(headless.InitCommand(NewRepoCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewRepoCredsCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(NewContextCommand(&clientOpts))
command.AddCommand(headless.InitCommand(NewProjectCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewAccountCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(NewLogoutCommand(&clientOpts))
command.AddCommand(headless.InitCommand(NewCertCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(headless.InitCommand(NewGPGCommand(&clientOpts), &clientOpts, nil, nil))
command.AddCommand(admin.NewAdminCommand()) |
I think I've come to the conclusion the only way to fix this for
@alexmt any better ideas? |
Actually, I think the cleaner approach would be to create a wrapper around |
For commands like the version --client, it doesn't have any subcommands and probably still needs hardcoded checks in Also I took a look at how cobra parses the command and for commands with subcommands, it appears that With this if we can make an assumption that all top-level commands will only perform actions when a subcommand is called and only display the
This would skip the hook execution if a top-level command is called without the subcommands and will display the help data. |
This is a more generalized solution and will work for any depth of subcommands but if there are subcommands without any more children commands that need to skip this hook that would need to an extra check like the version command. |
This is actually better as it only executes when a call to the server is needed. |
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
@jessesuen have updated the PR according to your suggestion, let me know if this is good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you group the imports such that we have:
- standard libs in one block
- 3rd party libs in 2nd block
- github.com/argoproj/argo-cd in the third block
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
Signed-off-by: Soumya Ghosh Dastidar <gdsoumya@gmail.com>
Signed-off-by: Soumya Ghosh Dastidar <soumya@akuity.io>
cmd/argocd/commands/account.go
Outdated
@@ -72,7 +74,7 @@ has appropriate RBAC permissions to change other accounts. | |||
c.HelpFunc()(c, args) | |||
os.Exit(1) | |||
} | |||
acdClient := argocdclient.NewClientOrDie(clientOpts) | |||
acdClient := headless.NewClientOrDie(clientOpts, initialize.RetrieveContextIfChanged(c.Flag("context"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can do this a little bit cleaner. Everywhere we repeat a call to initialize.RetrieveContextIfChanged
when initializing the client. i.e.:
headless.NewClientOrDie(clientOpts, initialize.RetrieveContextIfChanged(c.Flag("context")))
Can we somehow improve/reduce this to:
headless.NewClientOrDie(clientOpts)
Can we update the clientOpts to have a .context
field so we don't have to parse this everywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was initially thinking of doing that but this specific context is only required when we need to create the local server and the CLientOptions struct is a more general client pkg data that might be used by other API clients and binaries so I felt it might be better to keep it specific to the cli only instead of modifying the original struct. But we can add it in there too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point. But unfortunately, there's already a clientOpts.Core
which is a useless flag to the generic argocd client package. So for better or worse, we already have CLI specific flag which made its way into in clientOpts
.
If we want to be slightly cleaner about this, we could preserve the existing API client constructor. e.g.:
apiclient.NewClientOrDie(clientOpts)
And introduce a CLI specific constructor that accepts the cobra.Command
as a second argument:
headless.NewClientOrDie(clientOpts, c)
The headless.NewClientOrDie
would call:
initialize.RetrieveContextIfChanged(c.Flag("context"))
...
apiclient.NewClientOrDie(clientOpts)
Then we don't have to introduce more useless options to clientOpts
which aren't really used by the API client package. And we could even remove the Core option from clientOpts. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good to me, also we'll shift the headless.NewClientOrDie
to the CLI pkg so it will not technically change anything in the apiclient pkg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
pkg/apiclient/headless/headless.go
Outdated
"github.com/alicebob/miniredis/v2" | ||
"github.com/go-redis/redis/v8" | ||
"github.com/golang/protobuf/ptypes/empty" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/pflag" | ||
"k8s.io/apimachinery/pkg/util/runtime" | ||
"k8s.io/client-go/kubernetes" | ||
cache2 "k8s.io/client-go/tools/cache" | ||
"k8s.io/client-go/tools/clientcmd" | ||
"k8s.io/utils/pointer" | ||
|
||
"github.com/argoproj/argo-cd/v2/pkg/apiclient" | ||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" | ||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" | ||
repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" | ||
"github.com/argoproj/argo-cd/v2/server" | ||
servercache "github.com/argoproj/argo-cd/v2/server/cache" | ||
"github.com/argoproj/argo-cd/v2/util/cache" | ||
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate" | ||
"github.com/argoproj/argo-cd/v2/util/cli" | ||
"github.com/argoproj/argo-cd/v2/util/io" | ||
kubeutil "github.com/argoproj/argo-cd/v2/util/kube" | ||
"github.com/argoproj/argo-cd/v2/util/localconfig" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might be bringing in too many dependencies into pkg/apiclient
, which is meant to be a library/SDK. I think this package still belongs next to CLI code rather than library code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are okay with shifting the NewClientOrDie()
to the CLI (which should be okay because it's only used there) we can move this pkg to the cli part. NewClientOrDie needs to access the headless methods which if kept in the apiClient pkg separate from headless in cli, causes import cycles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are okay with shifting the NewClientOrDie() to the CLI (which should be okay because it's only used there) we can move this pkg to the cli part.
Spoke with @alexmt and he agrees that we should move this logic into CLI specific package to keep dependencies of pkg/apiclient leaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will shift it to CLI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
Signed-off-by: Soumya Ghosh Dastidar <soumya@akuity.io>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is much cleaner approach. Thank you!
pkg/apiclient/apiclient.go
Outdated
// NewClientOrDie creates a new API client from a set of config options, or fails fatally if the new client creation fails. | ||
func NewClientOrDie(opts *ClientOptions) Client { | ||
client, err := NewClient(opts) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
return client | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know we don't use this anymore in the CLI, but since it exists in pkg
i think we may want to keep this for other projects importing argo-cd as a library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes exactly, that's why I did not remove this incase someone else is already using it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait according to this diff. You did remove this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, I thought I moved the code around in the same pkg. Let me add it back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted it back.
Signed-off-by: Soumya Ghosh Dastidar <soumya@akuity.io>
Signed-off-by: Soumya Ghosh Dastidar gdsoumya@gmail.com
All commands call the PreRun hook and try to startup the local API server even when it's not required leading to the errors noticed. The proposed solution is to move the local API server creation from the PreRun hook into the
argocdclient.NewClientOrDie
call which will make sure the server is created only when a client needs to access it.#Fixes #7986
Checklist: